package com.hzw.saas.web.app.user.controller;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.hzw.saas.api.user.IUserAccountService;
import com.hzw.saas.api.user.IUserTripartiteService;
import com.hzw.saas.api.user.bo.UserAccountBO;
import com.hzw.saas.api.user.bo.UserWeTripartiteBO;
import com.hzw.saas.common.config.auth.param.WeChatTokenParam;
import com.hzw.saas.common.config.auth.param.WeChatUserInfoParam;
import com.hzw.saas.common.config.util.AssertUtil;
import com.hzw.saas.common.verify.service.IVerifyService;
import com.hzw.saas.service.property.enums.ModuleEnum;
import com.hzw.saas.web.app.user.dto.ResponseDto;
import com.hzw.saas.web.app.user.dto.TokenInfoDto;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 第三方用户表 前端控制器
 * </p>
 *
 * @author sonam
 * @since 2020-12-21
 */
@Slf4j
@RestController
@Api(tags = "用户中心/微信登录")
@RequestMapping("/user/oauth")
public class UserOAuthController {

    @Resource
    private AuthorizationServerTokenServices userTokenServices;

   @Autowired
    private IUserTripartiteService userWeChatService;

    @Autowired
    private IVerifyService verifyService;

    @Autowired
    private IUserAccountService userAccountService;

    // 查询用户逻辑
    @Resource
    private UserDetailsService userDetailsService;

    // 密码加密
    @Resource
    private PasswordEncoder passwordEncoder;


    @GetMapping("/wechat/sso")
    @ApiOperation("绑定微信号和用户id")
    public ResponseDto sso(
         @ApiParam("应用类型,前两位系统参数编号，三四位接入方编号，微信01，五六位平台编号，pc端01，app02，七八位对应服务的编号，05010101：网站鸿之微云，05010201：移动端hbox")@RequestParam("type") String type
        ,@ApiParam("手机号") @Param("phoneNum")  @RequestParam(required = false)String phoneNum
        , @ApiParam("邮箱") @Param("email")  @RequestParam(required = false)String email
         ,@ApiParam("密码") @Param("password") @RequestParam(required = false)String password
         ,@ApiParam("短信验证码")  @Param("code")@RequestParam(required = false)String code
        ,@ApiParam("openId") @RequestParam("openId")String openId
        ,@ApiParam("unionId")@RequestParam("unionId")String unionId) {
        AssertUtil.assertThrow("请输入手机号或者邮箱", StrUtil.isBlank(phoneNum) && StrUtil.isBlank(email));
        AssertUtil.assertThrow("请输入密码或者验证码",StrUtil.isBlank(code) && StrUtil.isBlank(password));
        boolean verifySms = false;
        boolean verifyEmail = false;
        ResponseDto responseDto = new ResponseDto();
        if (StrUtil.isBlank(password)){
            if (StringUtils.isNotBlank(phoneNum)) {
                verifySms = verifyService.verify(phoneNum, code, false);
            }
            if (StringUtils.isNotBlank(email)) {
                verifyEmail = verifyService.verify(email, code, false);
            }
            if (!verifySms && !verifyEmail){
                responseDto.setCode("0003");
                responseDto.setMsg("验证码错误");
                return responseDto;
            }
        }
        if (StrUtil.isBlank(type)){
            type = "";
        }
        String module = ModuleEnum.getDataByCode(type);
        if (module.equals("")){
            TokenInfoDto tokenInfoDto = new TokenInfoDto();
            tokenInfoDto.setBind(false);
            responseDto.setData(tokenInfoDto);
            responseDto.setCode("400");
            responseDto.setMsg("找不到对应的模块");
            return responseDto;
        }
        UserAccountBO userAccountBO = new UserAccountBO();
        if (StrUtil.isNotBlank(phoneNum)){
            userAccountBO = userAccountService.getAccountByPhone(phoneNum);
            if (userAccountBO.getUserId() == null ||userAccountBO.getUserId().equals("")){
                responseDto.setCode("0002");
                responseDto.setMsg("未注册");
                return responseDto;
            }
            if (StrUtil.isNotBlank(password)){
                    if (!passwordEncoder.matches(password, userAccountBO.getPassword())){
                        responseDto.setCode("0001");
                        responseDto.setMsg("密码错误");
                        return responseDto;
                    }
            }
        }
        if (StrUtil.isNotBlank(email)){
            userAccountBO = userAccountService.getByEmail(email);
            if (userAccountBO.getUserId() == null || userAccountBO.getUserId().equals("")){
                responseDto.setCode("0002");
                responseDto.setMsg("未注册");
                return responseDto;
            }
        }
        //判断账号是否已被绑定
        if (userWeChatService.ifByUserIdLikeType(userAccountBO.getUserId(), type)){
            responseDto.setCode("0005");
            responseDto.setMsg("账号已经被绑定，请先解绑或者联系客服");
            return responseDto;
        }
        List<UserWeTripartiteBO> byUnionIdAndOpenId = userWeChatService.getByUnionIdAndOpenId(unionId, openId, module);
        if (StrUtil.isNotBlank(userAccountBO.getUserId())&&StrUtil.isBlank(byUnionIdAndOpenId.get(0).getUserId())) {
            byUnionIdAndOpenId.get(0).setUserId(userAccountBO.getUserId());
            userWeChatService.updateById(byUnionIdAndOpenId.get(0));
        }
        TokenInfoDto tokenInfo = getTokenInfo(openId, unionId, type);
        responseDto.setCode("200");
        responseDto.setData(tokenInfo);
        responseDto.setMsg("success");
        return responseDto;
    }


    @GetMapping("/wechat/app/sso/{code}/{type}")
    @ApiOperation("根据code登陆")
    public ResponseEntity<TokenInfoDto> AppSSOByUnionIdAndOpenId(@ApiParam("code") @PathVariable("code") String code,
                                                                 @ApiParam("应用类型,前两位系统参数编号，三四位接入方编号，微信01，五六位平台编号，pc端01，app02，七八位对应服务的编号，05010101：网站鸿之微云，05010201：移动端hbox") @PathVariable("type") String type){
        if (StrUtil.isBlank(code)||StrUtil.isBlank(type)){
            log.debug("code："+code+","+"type :" +type );
            TokenInfoDto tokenInfoDto = new TokenInfoDto();
            tokenInfoDto.setBind(false);
            return ResponseEntity.ok(tokenInfoDto);
        }
        WeChatTokenParam wechatByCode = userWeChatService.getWechatByCode(code,type);
        if (wechatByCode == null||wechatByCode.getOpenid()== null ||wechatByCode.getUnionid() == null){
            log.debug("微信返回参数有误,请重试或者联系管理员");
            TokenInfoDto tokenInfoDto = new TokenInfoDto();
            tokenInfoDto.setBind(false);
            return ResponseEntity.ok(tokenInfoDto);
        }
        TokenInfoDto tokenInfo = getTokenInfo(wechatByCode.getOpenid(), wechatByCode.getUnionid(), type);
        if (tokenInfo.getNickname() == null){
            WeChatUserInfoParam weChatUserInfoParam = userWeChatService.getWeChatUserInfoParam(wechatByCode.getAccess_token(), wechatByCode.getOpenid(), wechatByCode.getUnionid(), type);
            if (weChatUserInfoParam != null&&weChatUserInfoParam.getNickname() != null) {
                tokenInfo.setNickname(weChatUserInfoParam.getNickname());
            }
        }
        return ResponseEntity.ok(tokenInfo);
    }


    private TokenInfoDto getTokenInfo(String openId,String unionId,String type){
        List<UserWeTripartiteBO> byUnionId = userWeChatService.getByUnionId(unionId);
        if (CollectionUtil.isEmpty(byUnionId)){
            UserWeTripartiteBO userWeTripartiteBO = new UserWeTripartiteBO();
            userWeTripartiteBO.setOpenId(openId);
            userWeTripartiteBO.setUnionId(unionId);
            userWeTripartiteBO.setModule(ModuleEnum.getDataByCode(type));
            userWeChatService.saveOne(userWeTripartiteBO);
        }
        List<String> collect = byUnionId.stream().filter((UserWeTripartiteBO u) -> u.getUserId() != null).map(UserWeTripartiteBO::getUserId).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(collect)){
            TokenInfoDto tokenInfoDto = new TokenInfoDto();
            tokenInfoDto.setBind(false);
            tokenInfoDto.setOpenId(openId);
            tokenInfoDto.setUnionId(unionId);
            return tokenInfoDto;
        }
        List<UserWeTripartiteBO> collect1 = byUnionId.stream().filter(o -> o.getUnionId().equals(unionId)).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(collect1)){
            TokenInfoDto tokenInfoDto = new TokenInfoDto();
            tokenInfoDto.setBind(false);
            tokenInfoDto.setOpenId(openId);
            tokenInfoDto.setUnionId(unionId);
            return tokenInfoDto;
        }else {
            //别的平台绑定了，同步其他平台的数据
            UserWeTripartiteBO userWeTripartiteBO = collect1.get(0);
            if (userWeTripartiteBO.getUserId()==null){
                userWeTripartiteBO.setUserId(collect.get(0));
                userWeChatService.updateById(userWeTripartiteBO);
            }
            TokenInfoDto tokenInfoDto = buildTokenInfo(userWeTripartiteBO);
            return tokenInfoDto;
        }

    }



    private TokenInfoDto buildTokenInfo(UserWeTripartiteBO userWeTripartiteBO){
        UserAccountBO account = userAccountService.getAccount(userWeTripartiteBO.getUserId());
        UserDetails user = userDetailsService.loadUserByUsername(account.getUserName());
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(user, account.getPassword(), user.getAuthorities());
        TokenRequest tokenRequest = new TokenRequest(null, null, Collections.singletonList("all"), null);
        OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(new BaseClientDetails());
        OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
        OAuth2AccessToken oAuth2AccessToken = userTokenServices.createAccessToken(oAuth2Authentication);
        TokenInfoDto tokenInfo = new TokenInfoDto();
        tokenInfo.setAccessToken(oAuth2AccessToken.getValue());
        tokenInfo.setExpiresIn(oAuth2AccessToken.getExpiresIn());
        tokenInfo.setTokenType("bearer");
        tokenInfo.setRefreshToken(oAuth2AccessToken.getRefreshToken().getValue());
        account.setPassword("");
        tokenInfo.setUserAccountBO(account);
        tokenInfo.setNickname(userWeTripartiteBO.getNickname() );
        tokenInfo.setBind(true);
        return tokenInfo;
    }

    @GetMapping("/wechat/sso/unbound/{user}/{type}")
    @ApiOperation("解除绑定绑定")
    public ResponseDto unBound(@ApiParam("用户id")@PathVariable("user")String user,
                                @ApiParam("应用类型,前两位系统参数编号，三四位接入方编号，微信01，五六位平台编号，pc端01，app02，七八位对应服务的编号，05010101：网站鸿之微云，05010201：移动端hbox")
                                @PathVariable("type")String type){
        ResponseDto responseDto = new ResponseDto();
        if (StrUtil.isBlank(user)||StrUtil.isBlank(type)){
            responseDto.setMsg("缺少系统指定参数，找不到用户id或者模块请联系关系员");
            responseDto.setCode("400");
            return responseDto;
        }
        String dataByCode = ModuleEnum.getDataByCode(type);
        if (StrUtil.isBlank(dataByCode)||!dataByCode.contains(".")){
            responseDto.setMsg("找不到对应模块");
            responseDto.setCode("200");
            return responseDto;
        }
        String substring = dataByCode.substring(0, dataByCode.indexOf("."));
        List<String> idsByUserIdLikeModule = userWeChatService.getIdsByUserIdLikeModule(user, substring);
        userWeChatService.deleteBatch(idsByUserIdLikeModule);
        responseDto.setCode("200");
        responseDto.setMsg("success");
        return responseDto;
    }

}
